﻿using Microsoft.EntityFrameworkCore;
using NewFormatProject.Repository.Interfaces;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace NewFormatProject.Repository.Instances
{
    public class Repository<T> : IRepository<T> where T : class, new()
    {
        protected readonly DbContext _dbContext;
        public Repository(DbContext dbContext)
        {
            _dbContext = dbContext;
        }
        /// <summary>
        /// 在传入方法中执行的所有操作都会被视为一个事务,错误仍然会抛出但事务会回滚。
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        public async Task ExecuteInTransactionAsync(Func<Task> action)
        {
            using var transaction = await _dbContext.Database.BeginTransactionAsync();

            try
            {
                await action();
                await transaction.CommitAsync();
            }
            catch (Exception)
            {
                await transaction.RollbackAsync();
                throw; // 重新抛出异常
            }
        }

        public Task<int> Add(T t)
        {
            TSet().Add(t);
            return Save();
        }

        public Task<int> Add(IEnumerable<T> ie)
        {
            TSet().AddRange(ie);
            return Save();
        }

        public Task<int> Delete(T t)
        {
            TSet().Remove(t);
            return Save();
        }

        public Task<int> Delete(IEnumerable<T> ie)
        {
            TSet().RemoveRange(ie);
            return Save();
        }

        public IQueryable<T> Pagination1<TKey>(Expression<Func<T, bool>> where, bool isAsc, Expression<Func<T, TKey>> order, out int total, int page, int limit)
        {
            var iq = Query(where);
            total = iq.Count();
            if (isAsc)
            {
                iq = iq.OrderBy(order);
            }
            else
            {
                iq = iq.OrderByDescending(order);
            }
            return iq.Skip((page - 1) * limit).Take(limit);
        }

        public IQueryable<T> Pagination2<TKey>(IQueryable<T> iq, Expression<Func<T, bool>> where, bool isAsc, Expression<Func<T, TKey>> order, out int total, int page, int limit)
        {
            iq = iq.Where(where);
            total = iq.Count();
            if (isAsc)
            {
                iq = iq.OrderBy(order);
            }
            else
            {
                iq = iq.OrderByDescending(order);
            }
            return iq.Skip((page - 1) * limit).Take(limit);
        }

        public IQueryable<T> Query()
        {
            return TSet();
        }

        public IQueryable<T> Query(Expression<Func<T, bool>> where)
        {
            return TSet().Where(where);
        }

        public IQueryable<T> Query<TKey>(Expression<Func<T, bool>> where, bool isAsc, Expression<Func<T, TKey>> order)
        {
            var iq = Query(where);
            if (isAsc)
            {
                iq = iq.OrderBy(order);
            }
            else
            {
                iq = iq.OrderByDescending(order);
            }
            return iq;
        }

        public async Task<int> Save()
        {
            return await _dbContext.SaveChangesAsync();
        }

        public DbSet<T> TSet()
        {
            return _dbContext.Set<T>();
        }



        private readonly List<string> ignoreUpdatePropertyName = new List<string>()
        {
            "CreateTime",
            "ParentId",
            "DepartmentId"
        };
        private bool IsIgnore(string name)
        {
            bool flag = false;
            foreach (var iName in ignoreUpdatePropertyName)
            {
                if (name.ToLower().Contains(iName.ToLower()))
                {
                    flag = true;
                    break;
                }
            }
            return flag;
        }
        public Task<int> UpdateAllProper(T t)
        {
            TSet().Update(t);
            return Save();
        }
        public Task<int> UpdateAllProper(IEnumerable<T> ie)
        {
            TSet().UpdateRange(ie);
            return Save();
        }

        public async Task<int> UpdateAllProperNotNull(T entity)
        {
            // 获取实体对象的类型
            Type entityType = typeof(T);

            // 获取实体对象的所有属性
            PropertyInfo[] properties = entityType.GetProperties();

            // 获取实体对象的所有属性值
            object[] values = properties.Select(p => p.GetValue(entity)).ToArray();

            // 获取实体的主键属性
            var primaryKey = _dbContext.Model.FindEntityType(entityType).FindPrimaryKey().Properties[0];

            // 获取实体的主键值
            var keyValue = primaryKey.PropertyInfo.GetValue(entity);

            // 查询数据库中对应的实体
            var dbEntity = await _dbContext.Set<T>().FindAsync(keyValue);

            if (dbEntity != null)
            {
                // 更新非空属性
                foreach (var property in properties)
                {
                    if (property != primaryKey.PropertyInfo && property.GetGetMethod() != null && !property.GetGetMethod().IsVirtual && !IsIgnore(property.Name) && values[properties.ToList().IndexOf(property)] != null)
                    {
                        property.SetValue(dbEntity, values[properties.ToList().IndexOf(property)]);
                    }
                }
            }

            return await Save(); // 假设更新成功
        }

        public async Task<int> UpdateAllProperNotNull(IEnumerable<T> entities)
        {
            // 获取实体对象的类型
            Type entityType = typeof(T);

            // 获取实体对象的所有属性
            PropertyInfo[] properties = entityType.GetProperties();

            // 获取实体的主键属性
            var primaryKey = _dbContext.Model.FindEntityType(entityType).FindPrimaryKey().Properties[0];

            foreach (var entity in entities)
            {
                // 获取实体对象的所有属性值
                object[] values = properties.Select(p => p.GetValue(entity)).ToArray();

                // 获取实体的主键值
                var keyValue = primaryKey.PropertyInfo.GetValue(entity);

                // 查询数据库中对应的实体
                var dbEntity = await _dbContext.Set<T>().FindAsync(keyValue);

                if (dbEntity != null)
                {
                    // 更新非空属性
                    foreach (var property in properties)
                    {
                        if (property != primaryKey.PropertyInfo && property.GetGetMethod() != null && !property.GetGetMethod().IsVirtual && !IsIgnore(property.Name) && values[properties.ToList().IndexOf(property)] != null)
                        {
                            property.SetValue(dbEntity, values[properties.ToList().IndexOf(property)]);
                        }
                    }
                }
            }

            // 保存更改
            return await Save();
        }

        public async Task<int> Transaction(Func<Task<int>> operation1, Func<Task<int>> operation2)
        {
            using (TransactionScope scope = new TransactionScope())
            {
                var isSuccess = true;
                var affectedRows = 0;
                // 执行数据库操作
                var temp = await operation1();
                if (temp == 0)
                {
                    isSuccess = false;
                }
                affectedRows += temp;
                temp = await operation2();
                if (temp == 0)
                {
                    isSuccess = false;
                }
                affectedRows += temp;
                if (isSuccess)
                {
                    scope.Complete(); // 完成事务
                    return affectedRows;
                }
                else
                {
                    return 0;
                }
            }
        }
    }
}
